package cn.exrick.xboot.common.qywxCode.Security;

import cn.exrick.xboot.common.annotation.SystemLog;
import cn.exrick.xboot.common.constant.CommonConstant;
import cn.exrick.xboot.common.constant.SecurityConstant;
import cn.exrick.xboot.common.enums.LogType;
import cn.exrick.xboot.common.utils.IpInfoUtil;
import cn.exrick.xboot.common.utils.ResponseUtil;
import cn.exrick.xboot.common.utils.SpringUtils;
import cn.exrick.xboot.common.vo.TokenUser;
import cn.exrick.xboot.modules.base.dao.PermissionDao;
import cn.exrick.xboot.modules.base.entity.Permission;
import cn.exrick.xboot.modules.base.entity.Role;
import cn.exrick.xboot.modules.base.entity.RolePermission;
import cn.exrick.xboot.modules.base.entity.User;
import cn.exrick.xboot.modules.base.service.RolePermissionService;
import cn.exrick.xboot.modules.base.service.RoleService;
import cn.exrick.xboot.modules.base.service.findUserByUsername;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Value("${xboot.token.redis}")
    private Boolean tokenRedis;

    @Value("${xboot.tokenExpireTime}")
    private Integer tokenExpireTime;

    @Value("${xboot.saveLoginTime}")
    private Integer saveLoginTime;

    @Value("${xboot.token.storePerms}")
    private Boolean storePerms;

    @Autowired
    private IpInfoUtil ipInfoUtil;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private PermissionDao permissionDao;

    @Autowired
    private findUserByUsername userService;

    @Override
    @SystemLog(description = "登录系统", type = LogType.LOGIN)
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        if (userService == null) {
            userService = (findUserByUsername) SpringUtils.getBean("findUserByUsernameImpl");
        }

        //用户选择保存登录状态天几
        String saveLogin = request.getParameter(SecurityConstant.SAVE_LOGIN);

        Boolean saved = false;
        if(StrUtil.isNotBlank(saveLogin) && Boolean.valueOf(saveLogin)){
            saved = true;
            if(!tokenRedis){
                tokenExpireTime = saveLoginTime * 60 * 24;
            }
        }
        //能得到用户名
        String username = request.getParameter("username");
        String idcardEncryption =((User) authentication.getPrincipal()).getIdcardEncryption() == null ? "" :((User) authentication.getPrincipal()).getIdcardEncryption();
        /*authentication.getDetails()*/
        List<GrantedAuthority> authorities ;
        User users = userService.findByUsername(username);
        if (users.getStatus().equals(CommonConstant.USER_STATUS_LOCK)){
            ResponseUtil.out(response, ResponseUtil.resultMap(false,500,"该用户已经被禁用！请联系管理员！"));
        }
        if (users != null) {
            authorities = (List<GrantedAuthority>) ((UserDetails)authentication.getPrincipal()).getAuthorities();
        }else {
            //权限设置为普通用户
            authorities = getAuthorities();
        }
        /*if (!"".equals(((UserDetails)authentication.getPrincipal()).getAuthorities()) || null != ((UserDetails)authentication.getPrincipal()).getAuthorities()){
            authorities = (List<GrantedAuthority>) ((UserDetails)authentication.getPrincipal()).getAuthorities();
        }else {
            //权限设置为普通用户
            authorities = getAuthorities();
        }*/

        List<String> list = new ArrayList<>();
        for(GrantedAuthority g : authorities){
            list.add(g.getAuthority());
        }

        logger.info("用户权限为:" + list.toString());
        ipInfoUtil.getUrl(request);
        // 登陆成功生成token
        String token;
        if(tokenRedis){
            // redis
            token = UUID.randomUUID().toString().replace("-", "");
            TokenUser user = new TokenUser(username, list, saved);
            // 不缓存权限
            if(!storePerms){
                user.setPermissions(null);
            }
            // 单点登录 之前的token失效
            String oldToken = redisTemplate.opsForValue().get(SecurityConstant.USER_TOKEN + username);
            if(StrUtil.isNotBlank(oldToken)){
                redisTemplate.delete(SecurityConstant.TOKEN_PRE + oldToken);
            }
            if(saved){
                redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, saveLoginTime, TimeUnit.DAYS);
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, new Gson().toJson(user), saveLoginTime, TimeUnit.DAYS);
            }else{
                redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenExpireTime, TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, new Gson().toJson(user), tokenExpireTime, TimeUnit.MINUTES);
            }
        }else{
            // 不缓存权限
            if(!storePerms){
                list = null;
            }
            // jwt
            token = SecurityConstant.TOKEN_SPLIT + Jwts.builder()
                    //主题 放入用户名
                    .setSubject(username)
                    //自定义属性 放入用户拥有请求权限
                    .claim(SecurityConstant.AUTHORITIES, new Gson().toJson(list))
                    //失效时间
                    .setExpiration(new Date(System.currentTimeMillis() + tokenExpireTime * 60 * 1000))
                    //签名算法和密钥
                    .signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
                    .compact();
        }
        redisTemplate.opsForValue().set(SecurityConstant.USER_IDCARDENCRYPTION + username,idcardEncryption, tokenExpireTime, TimeUnit.MINUTES);
        ResponseUtil.out(response, ResponseUtil.resultMap(true,200,"登录成功", token));
    }

    /**
     * @author    : LiYuanzhuo
     * description: 手动获取authorityList
     * create time: 2019/8/21 9:44
     */
    private List<GrantedAuthority> getAuthorities(){
        //获取默认角色
        List<GrantedAuthority> authorityList = new ArrayList<>();

        List<Role> roleList = roleService.findByDefaultRole(true);
        List<RolePermission> rolePermissionList = new ArrayList<>();
        for (Role role: roleList) {
            rolePermissionList = rolePermissionService.findByRoleId(role.getId());
        }
        List<Permission> permissionList = new ArrayList<>();
        List<Permission> permissionList2 = new ArrayList<>();
        for (RolePermission rp : rolePermissionList) {
            permissionList2 = permissionDao.findByParentIdOrderBySortOrder(rp.getPermissionId());
            for (Permission p: permissionList2) {
                permissionList.add(p);
            }
        }
        // 添加请求权限
        if(permissionList!=null&&permissionList.size()>0){
            for (Permission permission : permissionList) {
                if(CommonConstant.PERMISSION_OPERATION.equals(permission.getType())
                        &&StrUtil.isNotBlank(permission.getTitle())
                        &&StrUtil.isNotBlank(permission.getPath())) {

                    authorityList.add(new SimpleGrantedAuthority(permission.getTitle()));
                }
            }
        }
        // 添加角色
        if(roleList!=null&&roleList.size()>0){
            // lambda表达式
            roleList.forEach(item -> {
                if(StrUtil.isNotBlank(item.getName())){
                    authorityList.add(new SimpleGrantedAuthority(item.getName()));
                }
            });
        }
        return authorityList;
    }
}
